﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using T.ServiceComponent.Kernel.Service;
using T.ServiceComponent.Log.Client;
using T.ServiceComponent.Log.SPI;

namespace T.FAS.Runtime.Base.Common
{
    public class BigDataLogService
    {
        private static readonly object syncObj = new object();

        private readonly ConcurrentBag<ILog> logStore = null;

        private static BigDataLogService instance;

        private bool isExist = false;

        private AutoResetEvent autoResetLog;

        private readonly int capacity = 100000;

        private bool isFull = false;

        private BigDataLogService()
        {
            logStore = new ConcurrentBag<ILog>();
            autoResetLog = new AutoResetEvent(false);
            StartLogProcess();
        }

        public void Stop()
        {
            isExist = true;
            autoResetLog.Set();
        }

        public void Restart()
        {
            isExist = false;
            autoResetLog = new AutoResetEvent(false);
            StartLogProcess();
        }


        public static BigDataLogService GetInstance()
        {
            if (instance == null)
            {
                lock (syncObj)
                {
                    if (instance == null)
                    {
                        instance = new BigDataLogService();
                    }
                }
            }

            return instance;
        }

        public void AddLog(ILog log)
        {
            if (log == null) return;

            if (isFull)
            {
                return;
            }

            logStore.Add(log);
        }

        public void AddTraceLog(TrackLog log)
        {
            if (log == null) return;

            if (isFull)
            {
                return;
            }

            logStore.Add(log);
        }

        public void AddLogs(IEnumerable<ILog> logs)
        {
            if (logs == null || logs?.Count() == 0)
            {
                return;
            }

            if (isFull)
            {
                return;
            }

            foreach (var i in logs)
            {
                if (i != null)
                {
                    logStore.Add(i);
                }
            }
        }

        private void StartLogProcess()
        {
            Task.Factory.StartNew(() =>
            {
                //重新初始化一下RequestID，防止日志记录在正常链路中。
                //同时这些日志不需要记录全链路了，因为没有意义，所以初始化RequestID为空
                RpcContext.Current.RequestID = "";
                while (!isExist)
                {
                    var start = DateTime.Now;
                    var logs = new List<ILog>();
                    ILog log = null;
                    var index = 0;

                    if (logStore?.Count >= capacity)
                    {
                        isFull = true;
                    }
                    else
                    {
                        isFull = false;
                    }

                    if (logStore?.IsEmpty == false)
                    {
                        while ((DateTime.Now - start).TotalMilliseconds < 1000 && index < 100)
                        {
                            var result = logStore.TryTake(out log);
                            if (result && log != null)
                            {
                                index++;
                                logs.Add(log);
                            }
                        }
                    }
                    try
                    {
                        if (logs != null && logs.Count > 0)
                        {
                            AddLogToBigData(logs);
                            logs.Clear();
                            index = 0;
                        }
                        else
                        {
                            autoResetLog.WaitOne(1000);
                        }
                    }
                    catch { }
                }
            });
        }
        private void AddLogToBigData(List<ILog> logs)
        {
            using (var client = new LogLocalClient())
            {
                client.SendLogs(logs.ToArray());
            }
        }
    }
}
